using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using Raven.Abstractions.Extensions;
using System.ComponentModel;

namespace HotCopperUserScanService
{
    public class PostsTimer
    {
        private Timer _timer;
        private BindingList<Post> _postsDisplay;
        private readonly IStockForumBrowser _forumBrowser;

        public delegate void NewPostsEventHandler(object sender, List<Post> newPosts);
        public delegate void NewErrorsEventHandler(object sender, ICollection<string> newErrors);

        public event NewPostsEventHandler NewPostsEvent;
        public event NewErrorsEventHandler NewErrorsEvent;

        private Dictionary<string, string> users = new Dictionary<string, string>() 
                        { 
                            { "22600", "TimBosivic" },
                            { "8698", "gizard" },
                            { "2624", "martis" }
                        };

        public PostsTimer(IStockForumBrowser stockForum)
        {
            _forumBrowser = stockForum;
            Errors = new Collection<string>();
        }

        public BindingList<Post> PostsDisplay
        {
            get { return _postsDisplay; }
        }

        public Collection<string> Errors { get; private set; }

        private void TimerPulse(object state)
        {
            const string UserIDTag = "{USERID}";
            const string page = @"http://hotcopper.com.au/search/1099/?q=%2A&t=post&o=date&c[user][0]=" + UserIDTag;

            try
            {
                //check the login with the first dictionary item
                if (_forumBrowser.Login("caterer", "automaton", page.Replace(UserIDTag, users.First().Key)))
                {
                    foreach (var user in users)
                    {
                        var html = _forumBrowser.GetPageContent(new Uri(page.Replace(UserIDTag, user.Key)));
                        //use this to check for new errors - errors reading a page do not throw an exception but are recorded in Errors Collection
                        //Later on subscribers to the NewErrorsEvent are notified when new Errors are picked up
                        var errorCount = Errors.Count;
                        var posts = Parser.ExtractPosts(html, user.Value, _forumBrowser, 15, Errors).OrderByDescending(p => p.DateTime).ToArray();

                        var toInsert = new List<Post>();
                        var retrievedPosts = PostsDatabase.Retrieve(user.Value, posts.Length);
                        //any posts which aren't stored can be stored and notification provided
                        foreach (var post in posts)
                        {
                            var existingPost = retrievedPosts.FirstOrDefault(r => r.DateTime == post.DateTime);
                            if (existingPost == null)
                            {
                                toInsert.Add(post);
                            }
                            else
                            {
                                break;
                            }
                        }
                        if (toInsert.Any())
                        {
                            PostsDatabase.Insert(toInsert);
                            NewPostsEvent(this, toInsert);
                        }
                        if (errorCount < Errors.Count)
                        {
                            NewErrorsEvent(this, Errors);
                        }
                    }
                }
                else
                {
                    throw new ApplicationException("Unable to logon");
                }
            }
            catch (Exception ex)
            {
                //Record in the errors collection and try again next time
                Errors.Add(ex.Message);
                NewErrorsEvent(this, Errors);
            }

        }

        public void Start()
        {
            //PostsDatabase.InMemory = true;
            _postsDisplay = new BindingList<Post>(PostsDatabase.Retrieve(100).ToList());
            //start a timer to check 
            _timer = new Timer(TimerPulse, null, 0, 210000);
        }


        public void Stop()
        {
            PostsDatabase.CloseDown();
        }
    }

    
}